package edu.math.chaos.ui;

import edu.math.chaos.api.*;
import edu.math.chaos.params.ApplicationParameters;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.ScrollPane;
import javafx.scene.paint.Color;

/**
 * User: Илья
 * Date: 21.11.13
 * Time: 21:55
 */
public class DrawBoardController {

	private static final double MAX_ABSOLUTE_VALUE = 2;
	private static final double SQUARE_SIDE = 1;
	private static final int MAX_COLOR_COMPONENT = 255;

	@FXML
	private ScrollPane scroller;

	private ApplicationParameters params;
	private Canvas canvas;
	private CoordinatesConverter converter;
	private int maxIterations;

	@FXML
	public void initialize() {
		params = UIApplication.getApplicationParameters();
	}

	@FXML
	public void close(ActionEvent event) {
		UIApplication.close();
	}

	public void draw() {
		if (params == null) {
			return;
		}

		if (params.getN() < 0) {
			System.err.println("Число итераций должно быть неотрицательным");
			return;
		}

		try {
			WorldPoint leftBottom = new WorldPoint(params.getX1(), params.getY1());
			WorldPoint rightTop = new WorldPoint(params.getX2(), params.getY2());
			converter = new CoordinatesConverter(leftBottom, rightTop, params.getH());
			makeCanvas();
		} catch (Throwable e) {
			e.printStackTrace();
			return;
		}

		iteratePolinom();
	}

	private void makeCanvas() {
		ScreenPoint edgePoint = converter.getEdgeScreenPoint();
		canvas = new Canvas((edgePoint.getI() + 1) * SQUARE_SIDE, (edgePoint.getJ() + 1) * SQUARE_SIDE);
		scroller.setContent(canvas);
	}

	private void iteratePolinom() {
		IteratedPolinom polinom = new IteratedPolinom(new ComplexNumber(params.getCRe(), params.getCIm()));
		double worldX = params.getX1();
		double boundX = params.getX2();
		double boundY = params.getY2();
		double h = params.getH();
		maxIterations = params.getN();
		while (worldX <= boundX) {
			double worldY = params.getY1();
			while (worldY <= boundY) {
				ComplexNumber z = new ComplexNumber(worldX, worldY);
				polinom.setInitial(z);

				ComplexNumber current;
				double abs = z.getAbsoluteValue();
				int iterations = 0;
				while (abs <= MAX_ABSOLUTE_VALUE && iterations < maxIterations) {
					current = polinom.next();
					abs = current.getAbsoluteValue();
					iterations++;
				}
				fillPoint(z, iterations);

				worldY += h;
			}

			worldX += h;
		}
	}

	private void fillPoint(ComplexNumber complexPoint, int iterations) {
		// Малое число итераций для преодоления MAX_ABSOLUTE_VALUE соответствует точкам, наиболее
		// быстро стремящимся в бесконечность. Такие точки изображаются наиболее светлым цветом.
		// Наоборот, большое число итераций соответствует точкам, медленно стерящимся в бесконечность
		// либо вообще не стремящимся в бесконечность. Такие точки изображаются наиболее тёмным цветом.
		double factor = (double) (maxIterations - iterations) / maxIterations;
		int colorComponent = (int) (MAX_COLOR_COMPONENT * factor);
		Color color = Color.rgb(colorComponent, colorComponent, colorComponent);

		WorldPoint worldPoint = new WorldPoint(complexPoint);
		ScreenPoint screenPoint = converter.toScreenPoint(worldPoint);
		double canvasX = screenPoint.getI() * SQUARE_SIDE;
		double canvasY = screenPoint.getJ() * SQUARE_SIDE;

		GraphicsContext context = canvas.getGraphicsContext2D();
		context.setFill(color);
		context.fillRect(canvasX, canvasY, SQUARE_SIDE, SQUARE_SIDE);
	}
}
